﻿/*
	Copyright (C) 2019 Zongming Liu <1849059316@qq.com>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "GameWorld.h"
#include "../win32/Application.h"
#include "EngineEvent.h"
#include "EventManager.h"
#include "../utility/utility.h"
#include "../base/Scheduler.h"
#include "../node/Scene.h"
#include "../win32/ApplicationView.h"
#include "../action/ActionManager.h"
#include "../render/TextureCache.h"
#include "../ui/UiCore.h"
#include "../node/SpriteFrameCache.h"
#include "../base/EventManager.h"
#include "../audio/AudioManager.h"
#include "../ui/Text.h"
#include <string>
#include "../render/IRender.h"
#define SELF_DELETE(ptr) \
	delete ptr;    \
	ptr = nullptr;

namespace SkyEngine2d
{

	GameWorld::GameWorld()
		:m_renderInterface(nullptr)
		, m_appView(nullptr)
		, m_runningScene(nullptr)
		, m_timeScale(1.0)
		, m_audioManager(nullptr)
		, m_isOpenDebugConsole(false)
#ifdef _DEBUG
		, m_debugInfoFps(nullptr)
		, m_debugInfoVertexCount(nullptr)
		, m_debugInfoDrawCmd(nullptr)
		, m_debugInfoDrawCall(nullptr)
#endif // _DEBUG
		, m_isDisplayRenderInfo(false)
	{

	}

	GameWorld::~GameWorld()
	{

	}

	SkyEngine2d::IDirectRender* GameWorld::getDirectInterface() const
	{
		return m_d3dInterface;
	}

	bool GameWorld::init(IDirectRender* d3d, IRender* render, IApplicationView* app_view, Application* app)
	{
		m_app = app;
		m_appView = app_view;
		m_d3dInterface = d3d;
		m_renderInterface = render;

		m_Scheduler = new Scheduler;
		m_actionManager = new ActionManager;
		m_textureCache = new TextureCache;
		m_uiCore = new UiCore;
		m_defaultSpriteFrameCache = new SpriteFrameCache;
		m_eventManager = new EventManager;
		m_audioManager = new AudioManager;

#ifdef _DEBUG
		//初始化渲染信息的显示
		m_debugInfoFps = new Text;
		m_debugInfoDrawCall = new Text;
		m_debugInfoDrawCmd = new Text;
		m_debugInfoVertexCount = new Text;

		Font font(Font::defultFontFamily, 20);
		font.setAlignment(AlignLeft);

		m_debugInfoFps->setDrawRect(Rect(40, 100, Size(100, 50)));
		m_debugInfoFps->setColor(Color4f::White);
		m_debugInfoFps->setFont(font);

		m_debugInfoVertexCount->setDrawRect(Rect(40, 80, Size(100, 50)));
		m_debugInfoVertexCount->setColor(Color4f::White);
		m_debugInfoVertexCount->setFont(font);

		m_debugInfoDrawCmd->setDrawRect(Rect(40, 60, Size(100, 50)));
		m_debugInfoDrawCmd->setColor(Color4f::White);
		m_debugInfoDrawCmd->setFont(font);

		m_debugInfoDrawCall->setDrawRect(Rect(40, 40, Size(100, 50)));
		m_debugInfoDrawCall->setColor(Color4f::White);
		m_debugInfoDrawCall->setFont(font);
#endif // _DEBUG

		return true;
	}

	void GameWorld::end()
	{
		int count = m_sceneStack.size();
		for (int i = 0; i < count; i++)
		{
			m_sceneStack.pop();
		}

#ifdef _DEBUG
		SELF_DELETE(m_debugInfoDrawCall);
		SELF_DELETE(m_debugInfoVertexCount);
		SELF_DELETE(m_debugInfoDrawCmd);
		SELF_DELETE(m_debugInfoFps);
#endif // _DEBUG

		SELF_DELETE(m_Scheduler);
		SELF_DELETE(m_actionManager);
		SELF_DELETE(m_audioManager);
		SELF_DELETE(m_eventManager);
		SELF_DELETE(m_uiCore);
		SELF_DELETE(m_defaultSpriteFrameCache);
		SELF_DELETE(m_textureCache);
	}

	void GameWorld::mainLoop(double dt)
	{
		//统计fps
		m_fps = this->fps((float)dt);
		//虚拟时间
		float virtual_time_dt = (float)dt * m_timeScale;
		//1.处理动画
		m_actionManager->update(virtual_time_dt);
		//2.更新事件
		m_eventManager->eventLoop();
		//3.更新游戏逻辑
		m_Scheduler->update(virtual_time_dt);
		//4.遍历渲染树
		drawScene();
		//5.渲染
		renderScene();
	}

	SpriteFrameCache* GameWorld::getDefultSpriteFrameCache() const
	{
		return m_defaultSpriteFrameCache;
	}

	void GameWorld::popScene()
	{
		if (m_runningScene)
		{
			m_runningScene->quitScene();
		}
		if (m_sceneStack.size() > 0)
		{
			m_sceneStack.pop();
		}
		m_runningScene = nullptr;
	}

	void GameWorld::replaceScene(const std::shared_ptr<Scene>& scene)
	{
		this->popScene();
		this->pushScene(scene);
	}

	void GameWorld::start()
	{

	}

	void GameWorld::openDebugConsole()
	{
		if (!m_isOpenDebugConsole)
		{
			Debuger::getInstance()->init();
			m_isOpenDebugConsole = true;
		}
	}


	void GameWorld::isDisplayRenderInfo(bool display)
	{
		m_isDisplayRenderInfo = display;
	}

	void GameWorld::drawScene()
	{
		if (m_runningScene)
		{
			m_runningScene->visit(this->getRenderInterface(), false);
		}
#ifdef _DEBUG
		if (m_isDisplayRenderInfo)
		{
			this->displayRenderInfo();
		}
#endif // _DEBUG
	}

	void GameWorld::renderScene()
	{
		assert(m_renderInterface && "renderInterface 为 NULL ");
		m_renderInterface->renderBegin();

		m_renderInterface->render();

		auto hr = m_renderInterface->renderEnd();
		if (FAILED(hr))
		{
			DebugErr("致命错误! 渲染发生错误 ");
		}

	}

	void GameWorld::displayRenderInfo()
	{
#ifdef _DEBUG
		auto r = this->getRenderInterface();

		m_debugInfoFps->setText(std::wstring(L"FPS:") + std::to_wstring(m_fps));
		m_debugInfoDrawCmd->setText(std::wstring(L"DrawCmd:" + std::to_wstring(r->getDrawCmdCount())));
		m_debugInfoVertexCount->setText(std::wstring(L"VertexCount:") + std::to_wstring(r->getVertexCount()));
		m_debugInfoDrawCall->setText(std::wstring(L"DrawCall:") + std::to_wstring(r->getDrawCallCount()));

		m_debugInfoDrawCmd->draw(r);
		m_debugInfoDrawCall->draw(r);
		m_debugInfoVertexCount->draw(r);
		m_debugInfoFps->draw(r);
#endif // _DEBUG
	}

	int GameWorld::fps(float dt)
	{
		static int fps = 0;
		static int frameCount = 0;
		static float timeCount = 0;

		timeCount += dt;

		++frameCount;

		if (timeCount >= 1) // 取固定时间间隔为1秒
		{
			fps = frameCount;
			frameCount = 0;
			timeCount = 0;
		}
		return fps;
	}

	bool GameWorld::pushScene(const std::shared_ptr<Scene> & scene)
	{
		if (m_runningScene)
		{
			m_runningScene->quitScene();
		}

		if (!scene)
		{
			DebugWarning("场景为空指针");
			return false;
		}

		m_sceneStack.push(scene);

		m_runningScene = m_sceneStack.top().get();

		if (m_runningScene)
		{
			m_runningScene->enterScene();
		}

		return true;
	}
}

